home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-09-28 | 12.0 KB | 429 lines | [TEXT/CWIE] |
- /*
- File: NoCopyReceives.c
-
- Contains: Minimal sample to demo no-copy receives under OT.
-
- Written by: Quinn "The Eskimo!"
-
- Copyright: Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 7/22/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
-
-
- */
-
- /////////////////////////////////////////////////////////////////////
- // The OT debugging macros in <OTDebug.h> require this variable to
- // be set.
-
- #ifndef qDebug
- #define qDebug 1
- #endif
-
- /////////////////////////////////////////////////////////////////////
- // Pick up all the standard OT stuff.
- #include <Events.h>
- #include <Files.h>
- #include <OpenTransport.h>
- #include <OpenTptInternet.h>
-
- /////////////////////////////////////////////////////////////////////
- // Pick up no-copy receive stuff, which is not in "OpenTransport.h" because
- // it has no mixed mode glue.
-
- #include <OpenTptClient.h>
-
- /////////////////////////////////////////////////////////////////////
- // Pick up the OTDebugBreak and OTAssert macros.
-
- #include <OTDebug.h>
-
- /////////////////////////////////////////////////////////////////////
- // Standard C prototypes.
-
- #include <stdio.h>
-
- /////////////////////////////////////////////////////////////////////
- // OTDebugStr is not defined in any OT header files, but it is
- // exported by the libraries, so we define the prototype here.
-
- extern pascal void OTDebugStr(const char* str);
-
- /////////////////////////////////////////////////////////////////////
-
- static UInt32 gLastPrinted = 0;
-
- static pascal void YieldingNotifier(void* contextPtr, OTEventCode code,
- OTResult result, void* cookie)
- {
- #pragma unused(contextPtr)
- #pragma unused(result)
- #pragma unused(cookie)
-
- switch (code) {
- case kOTSyncIdleEvent:
- if ( TickCount() > gLastPrinted + 60 ) {
- printf(".");
- fflush(stdout);
- gLastPrinted = TickCount();
- }
- break;
- default:
- // do nothing
- break;
- }
- }
-
- /////////////////////////////////////////////////////////////////////
-
- enum {
- kTransferBufferSize = 1024
- };
-
- static char gTransferBuffer[kTransferBufferSize];
-
- static OSStatus NoCopyReceiveUsingOTReadBuffer(EndpointRef ep, SInt16 destFileRefNum)
- // Reads data from the endpoint using no-copy receive. The data
- // is then copied out of the OTBuffer chain using the OTReadBuffer utility
- // function. This method is useful if you need to look at a small chunk of
- // data (which you can copy out using OTReadBuffer) to decide what to do with
- // the rest.
- {
- OSStatus err;
- OTResult result;
- OTBuffer *receivedBuffer;
- OTBufferInfo bufferInfo;
- OTFlags junkFlags;
- UInt32 bytesRemaining;
- UInt32 bytesThisTime;
- SInt32 count;
-
- // Prepare for failure.
-
- err = noErr;
- receivedBuffer = nil;
-
- // Read the data. Use the constant kOTNetbufDataIsOTBufferStar to
- // indicate that you want to do a no-copy receive.
-
- result = OTRcv(ep, &receivedBuffer, kOTNetbufDataIsOTBufferStar, &junkFlags);
- if (result >= 0) {
-
- // Use the OT utility function OTBufferDataSize to calculate
- // how much data OT returned.
-
- bytesRemaining = OTBufferDataSize(receivedBuffer);
-
- // Initialise the bufferInfo data structure.
-
- bufferInfo.fOffset = 0;
- bufferInfo.fBuffer = receivedBuffer;
-
- // Write that data to the file. We do this in chunks,
- // copying each chunk of data out of the OTBuffer chain
- // and into our transfer buffer using the OTReadBuffer function,
- // then writing each chunk of data, until there is no
- // more data left in the buffer chain. This is not a
- // particularly efficient method (see below for something
- // better) but it does demonstrate the use of OTReadBuffer.
-
- while (err == noErr && bytesRemaining > 0) {
- if (bytesRemaining > kTransferBufferSize) {
- bytesThisTime = kTransferBufferSize;
- } else {
- bytesThisTime = bytesRemaining;
- }
- (void) OTReadBuffer(&bufferInfo, gTransferBuffer, &bytesThisTime);
- count = bytesThisTime;
- err = FSWrite(destFileRefNum, &count, gTransferBuffer);
- bytesRemaining -= bytesThisTime;
- }
-
- err = noErr;
- } else {
- err = result;
- }
-
- // Clean up. We *must* release the OTBuffer chain back to OT
- // so that it can reuse it. Also, OTReleaseBuffer is not tolerant of
- // the parameter being nil, so we check for that case first.
-
- if (receivedBuffer != nil) {
- OTReleaseBuffer(receivedBuffer);
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////////
-
- static OSStatus NoCopyReceiveWalkingBufferChain(EndpointRef ep, SInt16 destFileRefNum)
- // Reads data from the endpoint using no-copy receive. We walk
- // the resulting buffer chain, writing out chunks of data
- // directly to the file from the buffers returned to us by OT.
- {
- OSStatus err;
- OTResult result;
- OTBufferInfo bufferInfo;
- OTBuffer *thisBuffer;
- OTFlags junkFlags;
- SInt32 count;
-
- err = noErr;
-
- // Initialise the bufferInfo data structure.
-
- bufferInfo.fOffset = 0;
- bufferInfo.fBuffer = nil;
-
- // Read the data. Use the constant kOTNetbufDataIsOTBufferStar to
- // indicate that you want to do a no-copy receive.
-
- result = OTRcv(ep, &bufferInfo.fBuffer, kOTNetbufDataIsOTBufferStar, &junkFlags);
- if (result >= 0) {
-
- // Now walk the returned buffer chain, writing out each
- // chunk of data to the file.
-
- thisBuffer = bufferInfo.fBuffer;
- while (err == noErr && thisBuffer != nil) {
-
- count = thisBuffer->fLen;
- err = FSWrite(destFileRefNum, &count, thisBuffer->fData);
-
- thisBuffer = thisBuffer->fNext;
- }
-
- } else {
- err = result;
- }
-
- // Clean up. We *must* release the OTBuffer chain back to OT
- // so that it can reuse it. Also, OTReleaseBuffer is not tolerant of
- // the parameter being nil, so we check for that case first.
-
- if (bufferInfo.fBuffer != nil) {
- OTReleaseBuffer(bufferInfo.fBuffer);
- }
-
- return err;
- }
-
- /////////////////////////////////////////////////////////////////////
-
- enum {
- kUsingOTReadBuffer = 0,
- kUseWalkingBufferChain
- };
-
- static OSStatus TestNoCopyReceive(UInt8 method, SInt16 destFileRefNum)
- // Test the above two no-copy receive functions by connecting
- // to "www.apple.com" and downloading the root HTTP object.
- {
- OSStatus err;
- OSStatus junk;
- EndpointRef ep;
- DNSAddress hostDNSAddress;
- TCall sndCall;
- OTResult bytesSent;
- char httpGetCommand[256];
-
- // Create a TCP endpoint.
-
- ep = OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, nil, &err);
-
- // Set up the endpoint.
-
- if (err == noErr) {
-
- // Establish the modes of operation. This sample uses
- // sync/blocking mode, with sync idle events that yield
- // time using the Thread Manager.
-
- junk = OTSetSynchronous(ep);
- OTAssert("TestNoCopyReceive: OTSetSynchronous failed", junk == noErr);
-
- junk = OTSetBlocking(ep);
- OTAssert("TestNoCopyReceive: OTSetBlocking failed", junk == noErr);
-
- junk = OTInstallNotifier(ep, YieldingNotifier, nil);
- OTAssert("TestNoCopyReceive: OTInstallNotifier failed", junk == noErr);
-
- junk = OTUseSyncIdleEvents(ep, true);
- OTAssert("TestNoCopyReceive: OTUseSyncIdleEvents failed", junk == noErr);
-
- // Bind the endpoint. Because we're an outgoing connection,
- // we don't have to bind it to a specific address.
-
- err = OTBind(ep, nil, nil);
- }
-
- // Initialise the sndCall structure and call OTConnect. We nil
- // out most of the fields in the sndCall structure because
- // we don't want any special options or connection data.
- // The important field of the sndCall is the addr TNetBuf,
- // which we initialise to the address "www.apple.com:80"
- // (port 80 is the HTTP port).
-
- if (err == noErr) {
- OTMemzero(&sndCall, sizeof(TCall));
- sndCall.addr.buf = (UInt8 *) &hostDNSAddress;
- sndCall.addr.len = OTInitDNSAddress(&hostDNSAddress, "www.apple.com:80");
-
- err = OTConnect(ep, &sndCall, nil);
- }
-
- // Send the HTTP command to the web server.
-
- if (err == noErr) {
- (void) sprintf(httpGetCommand, "GET / HTTP/1.0%c%c%c%c", 13, 10, 13, 10);
-
- bytesSent = OTSnd(ep, (void *) httpGetCommand, OTStrLength(httpGetCommand), 0);
-
- // OTSnd returns the number of bytes sent. Because we're in
- // synchronous mode, it won't return until it's sent all the
- // bytes, or it gets an error.
-
- if (bytesSent > 0) {
- err = noErr;
- } else {
- err = bytesSent;
- }
- }
-
- // Now receive the response from the server and write it to the
- // destination file.
-
- if (err == noErr) {
-
- // No-copy receive does not really make sense in sync/blocking
- // mode, so we switch the endpoint to sync/non-blocking before.
- // proceeding. This is reasonable because you should not be using
- // no-copy receives unless you're looking for maximum speed,
- // and if you're looking for maximum speed you should be using
- // async/blocking mode, and doing everything in your notifier.
- // In this case, I'm just trying to demonstrate it's use, so
- // I make do with sync/non-blocking mode.
-
- junk = OTSetNonBlocking(ep);
- OTAssert("TestNoCopyReceive: OTSetNonBlocking failed", junk == noErr);
-
- do {
-
- // Depending on which method we were asked to use,
- // call the relevant receive function.
-
- switch (method) {
- case kUsingOTReadBuffer:
- err = NoCopyReceiveUsingOTReadBuffer(ep, destFileRefNum);
- break;
- case kUseWalkingBufferChain:
- err = NoCopyReceiveWalkingBufferChain(ep, destFileRefNum);
- break;
- default:
- OTDebugBreak("TestNoCopyReceive: What method?");
- err = -1;
- break;
- }
-
- // If we get kOTNoDataErr, that means we're still waiting for data,
- // so we just clear the error and continue looping.
-
- if (err == kOTNoDataErr) {
- YieldingNotifier(nil, kOTSyncIdleEvent, noErr, nil);
- err = noErr;
- }
- } while (err == noErr);
-
- // We will eventually leave the above loop with a kOTLookErr
- // because the endpoint received either a T_ORDREL or T_DISCONNECT
- // event. Either way, the data transfer is finished, so
- // we can just clear the error code and continue.
-
- if (err == kOTLookErr) {
- err = noErr;
- }
- }
-
- // I'm not going to bother cleaning up the endpoint cleanly.
- // This is the subject of another sample. For this sample, force
- // closing the endpoint is good enough.
-
- // Çlean up.
-
- if (ep != kOTInvalidEndpointRef) {
- junk = OTCloseProvider(ep);
- OTAssert("OTCloseProvider failed", junk == noErr);
- }
- return err;
- }
-
- /////////////////////////////////////////////////////////////////////
-
- void main(void)
- // The main line of the sample program. It creates
- // a file in the same directory as the sample called
- // "NoCopyReceive Test Output" and puts two copies
- // of the root HTTP object from "www.apple.com" into
- // that file.
- {
- OSStatus err;
- OSStatus junk;
- FSSpec fss;
- SInt16 destFileRefNum;
-
- printf("NoCopyReceives\n");
- printf("-- Download a URL using no-copy receives\n");
- printf("\n");
-
- err = InitOpenTransport();
-
- if (err == noErr) {
-
- // Create and open the output file.
-
- (void) FSMakeFSSpec(0, 0, "\pNoCopyReceive Test Output", &fss);
- (void) FSpCreate(&fss, 'R*ch', 'TEXT', 0);
- err = FSpOpenDF(&fss, fsRdWrPerm, &destFileRefNum);
-
- // Download two copies of the URL, one using the OTReadBuffer
- // method, the other by the buffer walking method.
-
- if (err == noErr) {
-
- printf("Downloading using OTReadBuffer method");
- err = TestNoCopyReceive(kUsingOTReadBuffer, destFileRefNum);
- printf("\n\n");
-
- if (err == noErr) {
- printf("Downloading using 'walk the buffer chain' method");
- err = TestNoCopyReceive(kUseWalkingBufferChain, destFileRefNum);
- printf("\n\n");
- }
-
- // Close the file.
-
- junk = FSClose(destFileRefNum);
- OTAssert("FSClose failed", junk == noErr);
- }
-
- CloseOpenTransport();
- }
-
- if (err == noErr) {
- printf("Success.\n");
- } else {
- printf("Failed with error %d.\n", err);
- }
- printf("Done. Press command-Q to Quit.\n");
- }
-